#include <kew/c-vm.h>
#include <kew/stdlib>

#define boolean_value(receiver) ((receiver)->type == kew_boolean_true_type)

/* Boolean representation.
 * There are actually 2 types: 1 for true values, and one for false ones.
 * There can be any number of instances of each type.
 */

#define DEFINE_BOOL_OP(NAME, OP, LOCATION) \
KEW_EXPORT_METHOD(NAME) \
{ \
    gboolean error; \
    KewObject *arg_cast = kew_type_cast(vm, args[0], kew_boolean_type, "boolean", sel_boolean, LOCATION, &error); \
    results[0] = error ? arg_cast : kew_boolean_new(boolean_value(receiver) OP boolean_value(arg_cast)); \
}


DEFINE_BOOL_OP(kew_boolean_and, &&, "Boolean>>and")
DEFINE_BOOL_OP(kew_boolean_or, ||, "Boolean>>or")

KEW_EXPORT_METHOD(kew_boolean_string)
{
    results[0] = kew_string_new(boolean_value(receiver) ? "True" : "False");
}

KEW_EXPORT_METHOD(kew_boolean_not)
{
    results[0] = kew_boolean_new(! boolean_value(receiver));
}

/* FIXME: got to here when editing */
KEW_EXPORT_METHOD(kew_boolean_thenElse)
{
    if (boolean_value(receiver))
        kew_send_full(env, NULL, args[0], sel_do, call_shape, 
}

KEW_METHOD(do_first)
{
  KewSend(args[0], "do", NULL, 0, results, num_results);
}

KEW_METHOD(do_second)
{
  KewSend(args[1], "do", NULL, 0, results, num_results);
}

KEW_METHOD(return_falses)
{
  int i;
  for (i = 0; i < num_results; ++i)
    results[i] = KewFalse;
}

KEW_METHOD(return_trues)
{
  int i;
  for (i = 0; i < num_results; ++i)
    results[i] = KewTrue;
}


KewObjectType KewTrueType = {
  __FILE__, __LINE__, sizeof(KewObject), 0,
  {
    {{"hash", 0, 1}, Kew__GenericHash},
    {{"=", 1, 1}, Kew__GenericEqual},
    {{"string", 0,1}, true_string},
    {{"boolean", 0,1}, identity},
    {{"not", 0,1}, return_falses},
    {{"and", 1,1}, true_and},
    {{"or", 1,1}, true_or},
    {{"then", 1,0}, do_first},
    {{"else", 1,0}, return_falses},
    {{"thenElse", 2,0}, do_first},
    {{"elseThen", 2,0}, do_second},
    {{NULL, 0, 0}, NULL}
  }
};

KewObjectType KewFalseType = {
  __FILE__, __LINE__, sizeof(KewObject), 0,
  {
    {{"hash", 0, 1}, Kew__GenericHash},
    {{"=", 1, 1}, Kew__GenericEqual},
    {{"string", 0,1}, false_string},
    {{"boolean", 0,1}, identity},
    {{"not", 0,1}, return_trues},
    {{"and", 1,1}, false_and},
    {{"or", 1,1}, false_or},
    {{"then", 1,0}, return_falses},
    {{"else", 1,0}, do_first},
    {{"thenElse", 2,0}, do_second},
    {{"elseThen", 2,0}, do_first},
    {{NULL, 0, 0}, NULL}
  }
};


void
Kew__InitBool(void)
{
  KewTrue = KewNewObject(&KewTrueType);
  KewFalse = KewNewObject(&KewFalseType);
}
